#pragma once
#include <mutex>
#include <functional>
#include <unordered_map>
#include "net.hpp"
#include "message.hpp"

namespace rpc
{
    class Callback
    {
    public:
        using ptr = std::shared_ptr<Callback>;
        virtual void onMessage(const BaseConnection::ptr & conn,BaseMessage::ptr & msg) = 0;
    };

    template<typename T>
    class CallbackT:public Callback
    {   
    public:
        using ptr = std::shared_ptr<CallbackT<T>>;
        using MessageCallback = std::function<void(const BaseConnection::ptr & conn,std::shared_ptr<T>&msg)>;
        CallbackT(const MessageCallback& handler):_handler(handler){}
        void onMessage(const BaseConnection::ptr & conn,BaseMessage::ptr & msg) override
        {
            auto type_msg = std::dynamic_pointer_cast<T>(msg);
            _handler(conn,type_msg);
        }
    private:
        MessageCallback _handler;//函数类型
    };

    //消息类型与回调的映射->第二个参数类型不确定->使用模板
    class Dispatcher
    {
    public:
        using ptr = std::shared_ptr<Dispatcher>;
        //注册消息类型与回调之间的关系
        template<typename T>
        void registerHandler(MType mtype, const typename CallbackT<T>::MessageCallback & handler)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto cb = std::make_shared<CallbackT<T>>(handler);
            _handers.insert(std::make_pair(mtype,cb));
        }

        //找到消息对应的业务处理函数,进行调用即可
        void onMessage(const BaseConnection::ptr & conn,BaseMessage::ptr & msg)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            std::unordered_map<MType,Callback::ptr>::iterator it = _handers.find(msg->mtype());//用父类来统一指向子类,调用onMessage
            if(it != _handers.end())
            {
                it->second->onMessage(conn,msg);//调用Callback的onMessage方法,onMessage方法里面进行向下转型
                return;
            }

            //没有找到指定的业务处理回调->客户端出现问题->关闭连接
            LOG(ERROR,"收到未知类型的消息");
            conn->shutdown();
        }
    private:
        std::mutex _mutex;
        std::unordered_map<MType,Callback::ptr> _handers;//将Callback设置为基类,即可存储多种类型的回调
    };
}